<!--
 * @Description: 第十一章 认识watchEffect高级侦听器
 * @Author: IA ia@kepro.space
 * @Date: 2025-02-12 15:59:59
-->
<template>
  <div>
    <p>watchEffect</p>
    <div>
      <p>基础例子</p>
      <div>
        <label>
          message_1_1:
          <input type="text" v-model="message_1_1" />
        </label>
        <label>
          message_1_2:
          <input type="text" v-model="message_1_2" />
        </label>
      </div>
    </div>
    <hr />
    <div>
      <p>清除副作用</p>
      <p>就是在触发监听之前会调用一个函数可以处理你的逻辑，例如防抖</p>
      <div>
        <p>优先执行回调函数</p>
        <label>
          message_2_1:
          <input type="text" v-model="message_2_1" />
        </label>
        <label>
          message_2_2:
          <input type="text" v-model="message_2_2" />
        </label>
      </div>

      <div>
        <p>停止跟踪 watchEffect</p>
        <label>
          message_3_1:
          <input type="text" v-model="message_3_1" />
        </label>
        <label>
          message_3_2:
          <input type="text" v-model="message_3_2" />
        </label>
        <button @click="stopWatch">停止侦听</button>
      </div>

      <div>
        <p>副作用刷新时机 flush</p>
        <div>
          <p>flush pre</p>
          <label>
            message_4_1_1:
            <input id="message_4_1_1_ipt" type="text" v-model="message_4_1_1" />
          </label>
          <label>
            message_4_1_2:
            <input type="text" v-model="message_4_1_2" />
          </label>
        </div>
        <div>
          <p>flush sync</p>
          <label>
            message_4_2_1:
            <input type="text" v-model="message_4_2_1" />
          </label>
          <label>
            message_4_2_2:
            <input id="message_4_2_2_ipt" type="text" v-model="message_4_2_2" />
          </label>
        </div>
        <div>
          <p>flush post</p>
          <label>
            message_4_3_1:
            <input id="message_4_3_1_ipt" type="text" v-model="message_4_3_1" />
          </label>
          <label>
            message_4_3_2:
            <input id="message_4_3_2_ipt" type="text" v-model="message_4_3_2" />
          </label>
        </div>
      </div>
    </div>
  </div>
</template>
<script setup lang="ts">
import { ref, reactive, watchEffect } from 'vue'

/*
  非惰性:  页面打开会立即执行传入的一个函数，同时响应式追踪其依赖，并在其依赖变更时重新运行该函数。
  更加抽象：使用时不需要具体指定监听的谁，回调函数内直接使用就可以
  不可访问之前的值：只能访问当前最新的值，访问不到修改之前的值
*/

let message_1_1 = ref<string>('message_1_1 value')
let message_1_2 = ref<string>('message_1_2 value')

watchEffect(() => {
  console.log('message_1_1: ', message_1_1.value)
  console.log('message_1_2: ', message_1_2.value)
})

let message_2_1 = ref<string>('message_2_1 value')
let message_2_2 = ref<string>('message_2_2 value')
watchEffect((oninvalidate) => {
  console.log('message_2_1: ', message_2_1.value)
  console.log('message_2_2: ', message_2_2.value)
  // 正常js是从上到下执行的，但是回调函数会先执行
  oninvalidate(() => {
    console.log('message_2 before')
  })
})

let message_3_1 = ref<string>('message_3_1 value')
let message_3_2 = ref<string>('message_3_2 value')

/*
当 watchEffect 在组件的 setup() 函数或生命周期钩子被调用时，侦听器会被链接到该组件的生命周期，并在组件卸载时自动停止。
在一些情况下，也可以显式调用返回值以停止侦听。
const stop 接收了watchEffect的调用的doWatch并返回doWatch的停止函数
通过stopWatch显示调用了stop进行停止侦听
*/
const stop = watchEffect((oninvalidate) => {
  console.log('message_3_1: ', message_3_1.value)
  console.log('message_3_2: ', message_3_2.value)
  oninvalidate(() => {
    console.log('!!!停止侦听 message_3!!!')
  })
})

const stopWatch = () => stop()

let message_4_1_1 = ref<string>('message_4_1_1 value')
let message_4_1_2 = ref<string>('message_4_1_2 value')

watchEffect(
  () => {
    let ipt: HTMLInputElement = document.querySelector('#message_4_1_1_ipt') as HTMLInputElement
    console.log('message_4_1 ipt', ipt)
    console.log('message_4_1_1: ', message_4_1_1.value)
    console.log('message_4_1_2: ', message_4_1_2.value)
  },
  {
    flush: 'pre', // 	组件更新前执行,
    onTrigger(e) {
      // 将在侦听器回调被依赖项的变更触发时被调用
      console.log('message_4_1 onTrigger: ', e)
      debugger
    },
  },
)

let message_4_2_1 = ref<string>('message_4_2_1 value')
let message_4_2_2 = ref<string>('message_4_2_2 value')

watchEffect(
  () => {
    console.log('message_4_2_1: ', message_4_2_1.value)
    console.log('message_4_2_2: ', message_4_2_2.value)
    let ipt: HTMLInputElement = document.querySelector('#message_4_2_2_ipt') as HTMLInputElement
    console.log('message_4_2 ipt', ipt)
  },
  {
    flush: 'sync', // 强制效果始终同步触发
    onTrigger(e) {
      // 将在侦听器回调被依赖项的变更触发时被调用
      console.log('message_4_2 onTrigger: ', e)
      debugger
    },
  },
)

let message_4_3_1 = ref<string>('message_4_3_1 value')
let message_4_3_2 = ref<string>('message_4_3_2 value')

watchEffect(
  () => {
    console.log('message_4_3_1: ', message_4_3_1.value)
    console.log('message_4_3_2: ', message_4_3_2.value)
    let ipt1: HTMLInputElement = document.querySelector('#message_4_3_1_ipt') as HTMLInputElement
    let ipt2: HTMLInputElement = document.querySelector('#message_4_3_2_ipt') as HTMLInputElement
    console.log('message_4_3 ipt1', ipt1)
    console.log('message_4_3 ipt2', ipt2)
  },
  {
    flush: 'post', // 组件更新后执行
    onTrigger(e) {
      // 将在侦听器回调被依赖项的变更触发时被调用
      console.log('message_4_3 onTrigger: ', e)
      debugger
    },
  },
)
</script>
<style scoped>
hr {
  margin: 10px 0;
}
</style>
